//
//  VPNService.m
//  alotOf
//
//  Created by Mac_Black_Mini on 2025/9/5.
//

#import "VPNService.h"
#import <AFNetworking/AFNetworking.h>

@interface VPNService ()

// 私有属性（仅内部管理）
@property (nonatomic, strong) NETunnelProviderManager *tunnelManager;
@property (nonatomic, strong) NSArray<Node *> *nodes;
@property (nonatomic, strong) Node *selectNode;
@property (nonatomic, assign) ConnectState connectState;
@property (nonatomic, assign) BOOL isConnecting;
@property (nonatomic, assign) NSInteger nextIndex;
@property (nonatomic, assign) NSInteger retryCount;
@property (nonatomic, strong) NSMutableArray<NSURLSessionDataTask *> *testNetTasks;
@property (nonatomic, assign) NSTimeInterval startConnectTime;
@property (nonatomic, assign) NSTimeInterval startTestTime;

@end

@implementation VPNService

static VPNService *instance;

+ (instancetype)shared {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[super allocWithZone:NULL] init];
        [instance initializeService];
    });
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self shared];
}

- (void)initializeService {
    // 初始化属性
    self.testNetTasks = [NSMutableArray array];
    self.connectState = ConnectStateDisconnect;
    // 监听VPN状态通知
    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(updateStatus)
                                               name:NEVPNStatusDidChangeNotification
                                             object:nil];
    // 加载系统VPN配置
    [self loadVPNPreference];
}

#pragma mark - 外部接口
- (void)setNodes:(NSArray<Node *> *)nodes {
    if (!nodes || nodes.count == 0) return;
    // 按权重排序（与原逻辑一致）
    NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"weights" ascending:NO];
    self.nodes = [nodes sortedArrayUsingDescriptors:@[sort]];
    // 默认选中第一个节点
    if (!self.selectNode) self.selectNode = self.nodes.firstObject;
}

- (void)startVPNWithNode:(Node *)node completion:(void (^)(NSError *))completion {
    // 1. 选择节点
    if (node) {
        self.selectNode = node;
        self.nextIndex = -1;
    } else {
        self.selectNode = self.nodes.firstObject;
        self.nextIndex = 0;
    }
    self.retryCount = 0;
    
    // 2. 校验节点
    if (!self.selectNode) {
        NSError *error = [NSError errorWithDomain:NSBundle.mainBundle.bundleIdentifier
                                            code:0
                                        userInfo:@{NSLocalizedDescriptionKey:@"无可用节点"}];
        completion(error);
        return;
    }
    
    // 3. 标记连接状态
    self.isConnecting = YES;
    self.connectState = ConnectStateConnecting;
    self.tunnelManager.enabled = YES;
    
    // 4. 保存配置并启动
    [self.tunnelManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
        if (error) {
            self.connectState = ConnectStateDisconnect;
            self.isConnecting = NO;
            completion(error);
            return;
        }
        [self.tunnelManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
            self.startConnectTime = NSDate.date.timeIntervalSince1970;
            if (self.tunnelManager.connection.status == NEVPNStatusDisconnected ||
                self.tunnelManager.connection.status == NEVPNStatusInvalid) {
                [self startVPN];
            } else {
                [self.tunnelManager.connection stopVPNTunnel];
            }
            completion(nil);
        }];
    }];
}

- (void)stopVPN {
    self.isConnecting = NO;
    [self cancelTestNetwork];
    [self.tunnelManager.connection stopVPNTunnel];
    self.connectState = ConnectStateDisconnect;
}

#pragma mark - 私有核心方法
- (void)loadVPNPreference {
    [NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArray<NETunnelProviderManager *> * _Nullable managers, NSError * _Nullable error) {
        if (error) {
            NSLog(@"VPN-> 加载配置失败：%@", error);
            return;
        }
        // 复用已有配置或创建新配置
        if (managers.firstObject) {
            self.tunnelManager = managers.firstObject;
        } else {
            self.tunnelManager = [[NETunnelProviderManager alloc] init];
            NETunnelProviderProtocol *protocol = [[NETunnelProviderProtocol alloc] init];
            protocol.providerBundleIdentifier = [Tools.bundleId stringByAppendingString:@".PacketTunnel"];
            self.tunnelManager.protocolConfiguration = protocol;
            self.tunnelManager.localizedDescription = Tools.appName;
            self.tunnelManager.protocolConfiguration.serverAddress = Tools.appName;
            // 保存新配置
            [self.tunnelManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
                if (error) NSLog(@"VPN-> 保存新配置失败：%@", error);
            }];
        }
        // 同步初始状态
        if (self.tunnelManager.connection.status == NEVPNStatusConnected) {
            self.connectState = ConnectStateConnected;
        }
    }];
}

- (void)startVPN {
    NSError *error;
    // 加载Sing-Box配置（与原逻辑一致）
    NSMutableDictionary *profile = [[self loadProfile] mutableCopy];
    if (!profile) return;
    
    // 替换出站节点
    NSMutableArray *outbounds = [(profile[@"outbounds"] ?: @[]) mutableCopy];
    [outbounds removeLastObject];
    NSDictionary *nodeInfo = self.selectNode.nodeInfo;
    [outbounds addObject:nodeInfo];
    profile[@"outbounds"] = outbounds;
    
    // 启动隧道
    [self.tunnelManager.connection startVPNTunnelWithOptions:@{
        @"nodeInfo": nodeInfo,
        @"profile": [Tools dictToString:profile]
    } andReturnError:&error];
    
    // 处理启动失败
    if (error) {
        NSLog(@"VPN-> 启动失败：%@", error);
        if (![self loadNextNode]) {
            [self stopVPN];
            return;
        }
        [self startVPN];
    }
}

- (NSDictionary *)loadProfile {
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"config" ofType:@"json"];
    if (!filePath) return nil;
    NSData *jsonData = [NSData dataWithContentsOfFile:filePath];
    if (!jsonData) return nil;
    NSError *error;
    return [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
}

- (void)updateStatus {
    NEVPNStatus status = self.tunnelManager.connection.status;
    switch (status) {
        case NEVPNStatusInvalid:
        {
            self.connectState = ConnectStateDisconnect;
        }
            break;
        case NEVPNStatusDisconnected:
        {
            if (self.isConnecting) [self startVPN];
            else self.connectState = ConnectStateDisconnect;
        }
            break;
        case NEVPNStatusConnected:{
            self.startTestTime = NSDate.date.timeIntervalSince1970;
            [self testNetworkCompletion:^(BOOL success) {
                if (!self.isConnecting) return;
                if (success) {
                    self.isConnecting = NO;
                    self.connectState = ConnectStateConnected;
                } else {
                    self.retryCount++;
                    if (self.retryCount >= 5 || ![self loadNextNode]) {
                        [self stopVPN];
                    } else {
                        [self.tunnelManager.connection stopVPNTunnel];
                    }
                }
            }];
        }
            
            break;
        default:
            break;
    }
}

#pragma mark - 辅助方法
- (BOOL)loadNextNode {
    self.nextIndex++;
    if (self.nextIndex < self.nodes.count) {
        self.selectNode = self.nodes[self.nextIndex];
        return YES;
    }
    return NO;
}

- (void)testNetworkCompletion:(void (^)(BOOL))completion {
    NSArray *testUrls = @[
        @"clients3.google.com/generate_204",
        @"ssl.gstatic.com/ui/v1/icons/mail/images/cleardot.gif",
        @"bat.bing.com/action/0",
        @"www.facebook.com/common/referer_frame.php",
        @"twitter.com/favicon.ico",
        @"http.cat/204",
        @"httpbin.org/status/204",
        @"cortney.ns.cloudflare.com",
        @"translate.google.com",
//        @"www.gstatic.com/generate_204",
//        @"www.google.com"
    ];
    dispatch_group_t group = dispatch_group_create();
    __block BOOL isSuccess = NO;
    
    [testUrls enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        dispatch_group_enter(group);
        NSString *url = [NSString stringWithFormat:@"https://%@", obj];

        AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
        manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
        manager.requestSerializer.timeoutInterval = 10;
        NSURLSessionDataTask *dataTask = [manager GET:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            NSLog(@"task-> success, url: %@, response: %@", url, responseObject);
            isSuccess = YES;
            [self cancelTestNetwork];
            dispatch_group_leave(group);
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            NSLog(@"task-> fail, url: %@, error: %@", url, error);
            dispatch_group_leave(group);
        }];
        [self.testNetTasks addObject:dataTask];
    }];
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        completion(isSuccess);
    });
}

- (void)cancelTestNetwork {
    [self.testNetTasks enumerateObjectsUsingBlock:^(NSURLSessionDataTask * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [obj cancel];
    }];
}

@end
